package com.andy.qi.service;

import java.util.HashMap;
import java.util.Map;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import com.andy.qi.controller.WebResult;
import com.andy.qi.domain.room.Room;
import com.andy.qi.domain.room.Seat;
import com.andy.qi.repository.RoomRepository;
import com.andy.qi.util.TimeUtils;

@Service
public class RoomMgr {
	
    Map<String, Room> rooms = new HashMap<>();
    Map<String, Boolean> creatingRooms = new HashMap<>();
    
    @Autowired private RoomRepository roomRepository;
    
    Map<String, RoomLocation> userLocation = new HashMap<>();
    int totalRooms = 0;
    
    int[] DI_FEN = {1,2,5};
    int[] MAX_FAN = {3,4,5};
    int[] JU_SHU = {4,8};
    int[] JU_SHU_COST = {2,3};
    
    @Autowired DBUtils db;
    @Autowired UserMgr userMgr;
    
    
    
    public Room constructRoomFromDb(Room roomInfo){
        if("xlch".equals(roomInfo.conf.type)){
            roomInfo.gameMgr = new GameOfXlch(this);
        } else {
            roomInfo.gameMgr = new GameOfXzdd(this);
        }
        String roomId = roomInfo.id;
        
        for(int i = 0; i < roomInfo.seats.length; i++) {
            Seat s = roomInfo.seats[i];
            if(s.userId != null){
                userLocation.put(s.userId, new RoomLocation(roomId, i ));
            }
        }
        rooms.put(roomId, roomInfo);
        totalRooms++;
        return roomInfo;
    }
    
    public WebResult createRoom(String creator, RoomConf roomConf, int gems, String ip, int port) {
        if(roomConf.type == null){
            return new WebResult(1, null);
        }
        
        if(roomConf.difen < 0 || roomConf.difen > DI_FEN.length){
            return new WebResult(1, null);
        }
        
        if(roomConf.zimo < 0 || roomConf.zimo > 2){
            return new WebResult(1, null);
        }
        
        if(roomConf.zuidafanshu < 0 || roomConf.zuidafanshu > MAX_FAN.length){
            return new WebResult(1, null);
        }
        
        if(roomConf.jushuxuanze < 0 || roomConf.jushuxuanze > JU_SHU.length){
            return new WebResult(1, null);
        }
        
        int cost = JU_SHU_COST[roomConf.jushuxuanze];
        if(cost > gems){
            return new WebResult(2222, null);
        }
        
        return fnCreate(creator, roomConf);
    }
    
    private WebResult fnCreate(String creator, RoomConf roomConf) {
        String roomId = Room.genId();
        if(rooms.get(roomId) != null || creatingRooms.get(roomId) != null){
            return fnCreate(creator, roomConf);
        } else {
            creatingRooms.put(roomId, true);
            if(roomRepository.existsById(roomId)){
                creatingRooms.remove(roomId);
                return fnCreate(creator, roomConf);
            }
            roomConf.baseScore = DI_FEN[roomConf.difen];
            roomConf.maxFan = MAX_FAN[roomConf.zuidafanshu];
            roomConf.maxGames = JU_SHU[roomConf.jushuxuanze];
            roomConf.creator = creator;
            
            int createTime = TimeUtils.now();
            Room room = new Room();
            room.setUuid(Room.genUuid());
            room.setId(roomId);
            room.createTime = createTime;
            room.nextButton = 0;
            room.conf = roomConf;
            
            if("xlch".equals(roomConf.type)){
                room.gameMgr = new GameOfXlch(this);
            } else{
                room.gameMgr = new GameOfXzdd(this);
            }
            
            Seat[] seats = new Seat[4];
            for(int i = 0; i < 4; ++i){
                seats[i] = new Seat(i);
            }
            room.seats = seats;
                    
            //写入数据库
            roomRepository.save(room);
            creatingRooms.remove(roomId);
            rooms.put(roomId, room);
            totalRooms++;
            return new WebResult(0, roomId);
            
        }
    }
    
    
    public void destroy(String roomId){
        Room room = rooms.get(roomId);
        if(room == null){
            return;
        }
        
        for(int i = 0; i < 4; ++i){
            String userId = room.seats[i].userId;
            if(userId != null){
                userLocation.remove(userId);
                db.set_room_id_of_user(userId,null);
            }
        }
        rooms.remove(roomId);
        room.gameMgr.destroy();
        totalRooms--;
        roomRepository.removeById(roomId);
    }
    
    public int getTotalRooms(){
        return totalRooms;
    }
    
    public Room getRoom(String roomId){
        return rooms.get(roomId);
    };
    
    public boolean isCreator(String roomId, String userId){
        Room room = rooms.get(roomId);
        if(room == null){
            return false;
        }
        return room.conf.creator.equals(userId);
    }
    
    public int fnTakeSeat(String roomId, String userId, String userName, Room room){
        if(roomId.equals(getUserRoom(userId))) {
            //已存在
            return 0;
        }
        
        for(int i = 0; i < 4; ++i){
            Seat seat = room.seats[i];
            if(seat.userId == null){
                seat.userId = userId;
                seat.name = userName;
                userLocation.put(userId, new RoomLocation(roomId, i));
                roomRepository.save(room);
                //正常
                return 0;
            }
        }
        //房间已满
        return 1;	
    }
    
    public int enterRoom(String roomId, String userId, String userName) {
        Room room = rooms.get(roomId);
        if(room != null) {
            return fnTakeSeat(roomId, userId, userName, room);
        }
        room = roomRepository.findOneById(roomId);
        if(room == null) {
            return 2;
        }
        //construct room.
        room = constructRoomFromDb(room);
        return fnTakeSeat(roomId, userId, userName, room);
    }
    
    public void setReady(String userId, boolean value){
        String roomId = getUserRoom(userId);
        if(roomId == null){
            return;
        }
        
        Room room = getRoom(roomId);
        if(room == null){
            return;
        }
        
        Integer seatIndex = getUserSeat(userId);
        if(seatIndex == null){
            return;
        }
        
        Seat s = room.seats[seatIndex];
        s.ready = value;
    }
    
    public boolean isReady(String userId){
        String roomId = getUserRoom(userId);
        if(roomId == null){
            return false;
        }
        
        Room room = getRoom(roomId);
        if(room == null){
            return false;
        }
        
        Integer seatIndex = getUserSeat(userId);
        if(seatIndex == null){
            return false;
        }
        
        Seat s = room.seats[seatIndex];
        return s.ready;
    }
    
    
    public String getUserRoom(String userId){
        RoomLocation location = userLocation.get(userId);
        if(location != null){
            return location.roomId;
        }
        return null;
    }
    
    public Integer getUserSeat(String userId) {
        RoomLocation location = userLocation.get(userId);
        if(location != null){
            return location.seatIndex;
        }
        return null;
    }
    
    public Map<String, RoomLocation> getUserLocations() {
        return userLocation;
    }
    
    public void exitRoom(String userId) {
        RoomLocation location = userLocation.get(userId);
        if(location == null)
            return;
        
        String roomId = location.roomId;
        int seatIndex = location.seatIndex;
        Room room = rooms.get(roomId);
        userLocation.remove(userId);
        if(room == null) {
            return;
        }
        Seat seat = room.seats[seatIndex];
        seat.userId = null;
        seat.name = "";
        
        int numOfPlayers = 0;
        for(int i = 0; i < room.seats.length; ++i){
            if(room.seats[i].userId != null){
                numOfPlayers++;
            }
        }
        
        db.set_room_id_of_user(userId, null);
        
        if(numOfPlayers == 0){
            destroy(roomId);
        }
    }
}